package com.retoc.oawx.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.retoc.oawx.common.SystemConstants;
import com.retoc.oawx.domain.Checkin;
import com.retoc.oawx.domain.FaceModel;
import com.retoc.oawx.exception.OAException;
import com.retoc.oawx.mapper.*;
import com.retoc.oawx.service.CheckinService;
import com.retoc.oawx.task.EmailTask;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

/**
* @author retoc
* @description 针对表【tb_checkin(签到表)】的数据库操作Service实现
* @createDate 2022-05-01 20:00:13
*/
@Service
@Slf4j
@Scope("prototype")
public class CheckinServiceImpl extends ServiceImpl<CheckinMapper, Checkin>
    implements CheckinService{

    @Autowired
    private SystemConstants constants;

    @Autowired
    private HolidaysMapper holidaysMapper;

    @Autowired
    private WorkdayMapper workdayMapper;

    @Autowired
    private CheckinMapper checkinMapper;

    @Autowired
    private FaceModelMapper faceModelMapper;
    
    @Autowired
    private CityMapper cityMapper;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private EmailTask emailTask;

    @Value("${oawx.face.createFaceModelUrl}")
    private String createFaceModelUrl;

    @Value("${oawx.face.checkinUrl}")
    private String checkinUrl;

    @Value("${oawx.email.hr}")
    private String hrEmail;

    @Value("${oawx.code}")
    private String code;

    @Override
    public String validCanCheckin(int userId, String date) {
        boolean isHoliday= holidaysMapper.searchTodayHolidays() != null;
        boolean isWorkday= workdayMapper.searchTodayIsWorkday() != null;
        String today = "工作日";
        if (DateUtil.date().isWeekend()) {
            today = "节假日";
        }
        if (isHoliday) {
            today = "节假日";
        } else if (isWorkday) {
            today = "工作日";
        }
        if (today.equals("节假日")) {
            return "节假日不需要考勤";
        } else {
            DateTime now=DateUtil.date();
            String start=DateUtil.today()+" "+constants.attendanceStartTime;
            String end=DateUtil.today()+" "+constants.attendanceEndTime;
            DateTime attendanceStart = DateUtil.parse(start);
            DateTime attendanceEnd = DateUtil.parse(end);
            if (now.isBefore(attendanceStart)) {
                return "还没到考勤开始时间";
            } else if (now.isAfter(attendanceEnd)) {
                return "已经超过考勤结束时间";
            } else {
                HashMap map = new HashMap();
                map.put("userId", userId);
                map.put("date", date);
                map.put("start",start);
                map.put("end",end);
                boolean result = checkinMapper.haveCheckin(map) != null;
                return result ? "已考勤，不需要重复考勤" : "可以考勤";
            }
        }
    }

    @Override
    public void checkin(HashMap param) {
        Date d1=DateUtil.date();
        Date d2=DateUtil.parse(DateUtil.today()+" " + constants.attendanceTime);
        Date d3=DateUtil.parse(DateUtil.today()+" " + constants.attendanceEndTime);
        int status=1;  //1为正常签到，2为迟到,3为请假
        if (d1.compareTo(d2)<=0){
            status=1;
        } else if (d1.compareTo(d2)>0&&d1.compareTo(d3)<0) {
            status=2;
        }
        int userId=(Integer)param.get("userId");
        String faceModel = faceModelMapper.searchFaceModel(userId);
        if (faceModel == null) {
            throw new OAException("不存在人脸模型");
        } else {
            String path = (String) param.get("path");
            HttpRequest request = HttpUtil.createPost(checkinUrl);
            request.form("photo", FileUtil.file(path),"targetModel",faceModel);
            request.form("code", code);
            HttpResponse response = request.execute();
            if (response.getStatus() != 200) {
                log.error("人脸识别服务异常");
                throw new OAException("人脸识别服务异常");
            }
            String body = response.body();
            if ("无法识别出人脸".equals(body) || "照片中存在多张人脸".equals(body)) {
                throw new OAException(body);
            } else if ("False".equals(body)) {
                throw new OAException("签到无效，请本人签到");
            } else if ("True".equals(body)) {

                int risk=1; //1为低风险，2为中，3为高
                String city = (String) param.get("city");
                String district = (String) param.get("district");
                String address = (String) param.get("address");
                String country = (String) param.get("country");
                String province = (String) param.get("province");
                if (!StrUtil.isBlank(city)&&!StrUtil.isBlank(district)){
                    String cityCode = cityMapper.selectCity(city);
                    try{
                        String url="http://m."+cityCode+".bendibao.com/news/yqdengji/?qu="+district;
                        Document document = Jsoup.connect(url).get();
                        Elements elements = document.getElementsByClass("list-content");
                        if (elements.size()>0){
                            Element element = elements.get(0);
                            String result = element.select("p:last-child").text();
//                            result="高风险";
                            if ("高风险".equals(result)) {
                                risk=3;
                                //发送警告邮件
                                HashMap<String, String> map = userMapper.searchNameDept(userId);
                                String name = map.get("name");
                                String dept = map.get("deptName");
                                dept = dept != null ? dept : "";
                                SimpleMailMessage message = new SimpleMailMessage();
                                message.setTo(hrEmail);
                                message.setText(dept + "员工" + name + "，" + DateUtil.format(new Date(), "yyyy年MM月dd日") + "处于" + address + "，属于新冠疫情高风险地区，请及时与该员工联系，核实情况！");
                                emailTask.sendAsync(message);
                            } else if ("中风险".equals(result)) {
                                risk=2;
                            }
                        }
                    }catch (Exception e){
                        log.error("执行异常",e);
                        throw new OAException("获取风险等级失败");
                    }
                }
                //保存签到记录
                Checkin checkin = new Checkin();
                checkin.setUserId(userId);
                checkin.setAddress(address);
                checkin.setCountry(country);
                checkin.setProvince(province);
                checkin.setCity(city);
                checkin.setDistrict(district);
                checkin.setStatus(status);
                checkin.setDate(DateUtil.today());
                checkin.setRisk(risk);
                checkin.setCreateTime(d1);
                checkinMapper.insertCheckin(checkin);
                System.out.println("成功！");
            }
        }
    }

    @Override
    public void leaveCheckin(HashMap param) {
        int user =(int) param.get("userId");
        String start =(String) param.get("startDate");
        DateTime startDate = DateUtil.parseDate(start);
        String end =(String) param.get("endDate");
        DateTime endDate = DateUtil.parseDate(end);
        DateRange range = DateUtil.range(startDate, endDate, DateField.DAY_OF_MONTH);
        ArrayList<String> holidayList = holidaysMapper.searchHolidaysInRange(param);
        ArrayList<String> workdayList = workdayMapper.searchWorkdayInRange(param);
        range.forEach(day->{
            String date=day.toString("yyyy-MM-dd");
            //初始化type为工作日
            String type="工作日";
            //如果为周末则改成节假日
            if (day.isWeekend()){
                type="节假日";
            }
            //如果之前查询的特殊假日表中含有当天，则必定为节假日
            if (holidayList != null && holidayList.contains(date)) {
                type="节假日";
            }
            //如果之前查询的特殊工作日表中含有当天，则必定为工作日
            else if (workdayList != null && workdayList.contains(date)) {
                type="工作日";
            }
//            如果请假期间的日期为工作日，则在checkin表中添加一条状态为3的记录，即请假记录
            if (type.equals("工作日")){
                Checkin checkin = new Checkin();
                checkin.setUserId(user);
                checkin.setStatus(3);
                checkin.setDate(date);
            }
        });
    }


    @Override
    public void createFaceModel(int userId, String path) {
        HttpRequest request = HttpUtil.createPost(createFaceModelUrl);
        request.form("photo", FileUtil.file(path));
        request.form("code", code);
        HttpResponse response=request.execute();
        String body = response.body();
        if ("无法识别出人脸".equals(body) || "照片中存在多张人脸".equals(body)) {
            throw new OAException(body);
        }
        else {
            FaceModel faceModel=new FaceModel();
            faceModel.setUserId(userId);
            faceModel.setFaceModel(body);
            faceModelMapper.insertFaceModel(faceModel);
        }
    }

    @Override
    public HashMap searchTodayCheckin(int userId) {
        return checkinMapper.searchTodayCheckin(userId);
    }

    @Override
    public long searchCheckinDays(int userId) {
        return checkinMapper.searchCheckinDays(userId);
    }

    @Override
    public ArrayList<HashMap> searchWeekCheckin(HashMap param) {
        ArrayList<HashMap> checkinList = checkinMapper.searchWeekCheckin(param);
        ArrayList<String> holidayList = holidaysMapper.searchHolidaysInRange(param);
        ArrayList<String> workdayList = workdayMapper.searchWorkdayInRange(param);

        DateTime startDate = DateUtil.parseDate(param.get("startDate").toString());
        DateTime endDate = DateUtil.parseDate(param.get("endDate").toString());
        DateRange range = DateUtil.range(startDate, endDate, DateField.DAY_OF_MONTH);
        ArrayList<HashMap> list = new ArrayList<>();
        range.forEach(one->{
            String date=one.toString("yyyy-MM-dd");
            //初始化type为工作日
            String type="工作日";
            //如果为周末则改成节假日
            if (one.isWeekend()){
                type="节假日";
            }
            //如果之前查询的特殊假日表中含有当天，则必定为节假日
            if (holidayList != null && holidayList.contains(date)) {
                type="节假日";
            }
            //如果之前查询的特殊工作日表中含有当天，则必定为工作日
            else if (workdayList != null && workdayList.contains(date)) {
                type="工作日";
            }
            //定义上班状态status
            String status="";
            //如果当天为工作日且与今天比较为已过去的日期，则上班状态为缺勤
            if (type.equals("工作日")&&DateUtil.compare(one,DateUtil.date())<=0){
                //设置签到状态默认为缺勤
                status = "缺勤";
                //设置一个flag变量标记今天是否有签到
                boolean flag=false;
                //循环查询checkinList中如果有当天日期，则把签到状态改成与表中一致，把标记改为已签到并终止该循环
                for (HashMap<String, String> map : checkinList) {
                    if (map.containsValue(date)){
                        status = map.get("status");
                        flag=true;
                        break;
                    }
                }
                //判断如果日期为今天，但是还没到签到结束时间且当天还没打卡，则签到状态为空
                DateTime endTime = DateUtil.parse(DateUtil.today() + " " + constants.attendanceEndTime);
                if (date.equals(DateUtil.today()) && DateUtil.date().isBefore(endTime) && !flag) {
                    status = "";
                }
            }
            /**
             * 循环中的签到状态：
             * 1.如果当天不为工作日，checkinList中不存在记录，则status为空
             * 2.如果当天为工作日，先默认为缺勤，然后再checkinList查找是否有记录，如果有，则把签到状态改成跟checkinList中一致（正常或迟到）
             * 3.如果当天为工作日，且日期为今天，且考勤时间还没过，则把签到状态改成空
             */
            HashMap map = new HashMap();
            map.put("date", date);
            map.put("status", status);
            map.put("type", type);
            map.put("day", one.dayOfWeekEnum().toChinese("周"));
            list.add(map);
        });
        return list;
    }

    @Override
    public ArrayList<HashMap> searchMonthCheckin(HashMap param) {
        return this.searchWeekCheckin(param);
    }


}




